#ifndef _HWINFO_H_
#define _HWINFO_H_

#include <cstdio>
#include <string>
#include <memory>

#include "types.h"
#include "biosInfo.h"
#include "systemInfo.h"
#include "baseboardInfo.h"
#include "chassisInfo.h"
#include "processorInfo.h"

// https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.8.0.pdf

class HwInfo {
    struct DmiHeader {
        UINT8 type;
        UINT8 length;
        UINT16 handle;
        UINT8 *data;
    };

    enum CpuidType {
        CPUID_NONE,
        CPUID_80386,
        CPUID_80486,
        CPUID_ARM_LEGACY,
        CPUID_ARM_SOC_ID,
        CPUID_X86_INTEL,
        CPUID_X86_AMD,
        CPUID_LOONGARCH,
    };

    enum DMI_VENDORS {
        VENDOR_UNKNOWN,
        VENDOR_ACER,
        VENDOR_HP,
        VENDOR_HPE,
        VENDOR_IBM,
        VENDOR_LENOVO,
    };

public:
    enum Status {
        FAILED = -1,
        SUCCEED,
        EXIT = 255
    };

public:
    HwInfo() : _smbiosEntryPoint("/sys/firmware/dmi/tables/smbios_entry_point"), 
               _dmiPath("/sys/firmware/dmi/tables/DMI"),
               _dmiVendor(VENDOR_UNKNOWN), _cpuidType(CPUID_NONE){}
    
    int             calculate();

private:
    UINT8*          readFile(const std::string& filename, off_t base, size_t &max_len);

    int             checkSum(const UINT8 *buf, size_t len) const;

    int             smbiosDecode(std::unique_ptr<UINT8[]>& buf, size_t bufLen, const std::string& devmem, UINT32 flags);

    void            asciiFilter(char *bp, size_t len) const;

    void            dmiGetHeader(DmiHeader &h, UINT8 *data) const;
    void            dmiFixupVersion(UINT16 &ver) const;
    void            dmiTableDecode(UINT8 *buf, UINT32 len, UINT16 num, UINT16 ver, UINT32 flags);
    UINT8*          dmiGetTable(off_t base, UINT32 &len, UINT16 num, UINT32 ver, const std::string &devmem, UINT32 flags);
    char*           dmiString(const DmiHeader &dm, UINT8 s, int filter);
    const char*     dmiString(const DmiHeader& dm, UINT8 s);
    void            dmiSetVendor(const char *v, const char *p);
    int             dmiGetCpuidType(const DmiHeader &h);
    void            dmiFixupType34(DmiHeader &h);
    // main decode function
    void            dmiDecode(const DmiHeader &h, UINT16 ver);

    int             isPrintable(const UINT8 *data, int len) const;

private:
    std::string     _smbiosEntryPoint;
    std::string     _dmiPath;
    int             _dmiVendor;
    std::string     _dmiProduct;
    int             _cpuidType;

    // decode smbios informations.
    BiosInfos       _biosInfos;
    SystemInfo      _systemInfos;
    BaseboardInfo   _baseBoardInfos;
    ChassisInfo     _chassisInfos;
    ProcessorInfo   _processorInfo;
};

#endif